﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System.Collections.Generic;
using Core.Parsing.ContextFree;

namespace Core.Json
{
    using T = JsonLexer;
    using SVal = IDictionary<string, object>;

    public static class JsonGrammar
    {
        private static readonly Grammar<SVal> G;

        static JsonGrammar()
        {
            var Object = new Nonterminal<SVal>("object");
            var MemberList = new Nonterminal<SVal>("member-list");
            var Member = new Nonterminal<Tuple<string, object>>("member");
            var Array = new Nonterminal<IEnumerable<object>>("array");
            var Elements = new Nonterminal<List<object>>("elements");
            var Value = new Nonterminal<object>("value");

            Object.add(JsonLexer.L_BRACE, JsonLexer.R_BRACE, (l, r) => new Dictionary<string,object>());
            Object.add(JsonLexer.L_BRACE, MemberList, JsonLexer.R_BRACE, (l, m, r) => m);

            MemberList.add(Member, m => new Dictionary<string, object> { { m.Item1, m.Item2 } });
            MemberList.add(MemberList, JsonLexer.COMMA, Member, (l, c, m) =>
                                                                    {
                                                                        l.Add(m.Item1, m.Item2);
                                                                        return l;
                                                                    });

            Member.add(JsonLexer.STRING, JsonLexer.COLON, Value, (n, c, v) => Tuple.New(n, v));

            Array.add(JsonLexer.L_BRACKET, JsonLexer.R_BRACKET, (l, r) => new object[0]);
            Array.add(JsonLexer.L_BRACKET, Elements, JsonLexer.R_BRACKET, (l, e, r) => e);

            Elements.add(Value, v => new List<object> { v });
            Elements.add(Elements, JsonLexer.COMMA, Value, (e, c, v) =>
                                                               {
                                                                   e.Add(v);
                                                                   return e;
                                                               });

            Value.add(JsonLexer.STRING);
            Value.add(JsonLexer.FLOAT);
            Value.add(JsonLexer.INT);
            Value.add(Object);
            Value.add(Array);
            Value.add(JsonLexer.TRUE);
            Value.add(JsonLexer.FALSE);
            Value.add(JsonLexer.NULL);

            G = new Grammar<SVal>(Object);
        }

        public static Grammar<SVal> Grammar
        {
            get { return G; }
        }
    }
}